﻿using System;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using MessageRouter.Configuration;
using MessageRouter.ServiceBroker.Activation;
using MessageRouter.ServiceBroker.Configuration;

namespace MessageRouter.ServiceBroker
{
    internal sealed class ServiceBrokerMessageReader : MessageReader
    {
        private readonly ServiceBrokerMessageReaderConnectionFactory connectionFactory;
        private readonly ServiceBrokerMessageReaderCommandFactory commandFactory;
        private readonly ServiceBrokerMessageReaderActivator activator;

        public ServiceBrokerMessageReader(ReaderConfigurationElement config)
            : base(config)
        {
            ServiceBrokerEndpointAddress endpointAddress = new ServiceBrokerEndpointAddress(config.Address);
            var behaviorConfig = ConfigurationManager.Current.Behaviors.FirstOrDefault(behavior => behavior.Name == config.Behavior);

            if (behaviorConfig == null)
            {
                throw new ArgumentNullException("behavior");
            }

            this.connectionFactory = new ServiceBrokerMessageReaderConnectionFactory(endpointAddress);
            this.commandFactory = new ServiceBrokerMessageReaderCommandFactory(endpointAddress, behaviorConfig.DialogLifetimePolicy);
            this.activator = (ServiceBrokerMessageReaderActivator)Activator.CreateInstance(behaviorConfig.Activator, new object[] { endpointAddress });
            this.activator.Activation += OnActivation;
        }

        protected override bool TryRead(out RoutedMessage routedMessage)
        {
            bool result = false;

            using (SqlConnection connection = this.connectionFactory.Create())
            using (SqlCommand command = this.commandFactory.CreateCommand(connection))
            {
                connection.Open();
                using (SqlDataReader dataReader = command.ExecuteReader())
                {
                    routedMessage = (result = dataReader.Read())
                        ? new RoutedMessage(dataReader.GetGuid(0), dataReader.GetString(1), dataReader[2])
                        : null;
                }
            }
            return result;
        }

        protected override void OnError(Exception error)
        {
            Trace.TraceError("ServiceBrokerMessageReader failed with error: {0}", error.Message);
        }

        protected override void OnOpened()
        {
            this.activator.Open();
        }

        protected override void OnClosing()
        {
            this.activator.Close();
        }

        private void OnActivation(object sender, EventArgs e)
        {
            base.OnActivationCompleted();
        }
    }
}
